// SINGULARITY HTML5 GAME ENGINE
// -----------------------------
// Copyright(c) 2013 by Codenova.pl

define([], function () {
    var Core = function () {};
    var _Core = function() {};

    _Core.prototype = {
        /**
         * Creates audio tag for given element
         * @param element
         * @constructor
         */
        CreateAudioTag: function(element) {
            "use strict";
            // If element has audio playing on hover, create audio tag for it
            if(typeof element.Hover !== "undefined") {
                if(typeof element.Hover.Audio !== "undefined") {
                    var el = document.createElement('audio');
                    el.setAttribute('id', element.Id);
                    el.setAttribute('src', 'audio/' + element.Hover.Audio + '.mp3');
                    document.getElementById('body').appendChild(el);
                }
            }
        }
    };

    Core.prototype = {
        /**
         * Center given element relatively to parent
         * @return {number}
         * @return {number}
         */
        CenterDimension: function(dimension, parentDimension, elementDimension) {
            "use strict";
            return (dimension === 'auto') ? parentDimension / 2 - elementDimension / 2 : dimension;
        },

        /**
         * Center element relatively to window
         * @return {number}
         * @return {number}
         */
        CenterDimensionToWindow: function(dimension, elementDimension, dimensionName) {
            "use strict";
            if (dimensionName == 'width') {
                return (dimension === 'auto') ? dimension = window.innerWidth / 2 - elementDimension / 2 : dimension;
            }
            return (dimension === 'auto') ? dimension = window.innerHeight / 2 - elementDimension / 2 : dimension;
        },

        /**
         * Clear canvas with given parameters
         * @param ctx
         * @param width
         * @param height
         * @constructor
         */
        ClearCanvas: function(ctx, width, height) {
            ctx.clearRect(0, 0, width, height);
        },

        /**
         * Creates audio tag for given element
         * @param element
         * @constructor
         */
        CreateAudioTag: function(element) {
            var _i, _length;

            if(typeof element.Inputs === 'undefined') {
                _Core.prototype.CreateAudioTag(element);
            }

            // Check if it is extended object
            if(typeof element.Inputs !== 'undefined') {
                if(element.Inputs.length > 0) {
                    for(_i = 0, _length = element.Inputs.length - 1; _i <= _length; _i = _i + 1) {
                        _Core.prototype.CreateAudioTag(element.Inputs[_i]);
                    }
                }
            }
        },

        CreateCanvasForElement: function(el, attributeName, attributeValue) {
            var elId;

            // Set element's ID
            if(typeof el.InputType !== 'undefined') {
                elId = el.InputType + '-' + el.Id;
            } else if(typeof el.ElementType !== 'undefined') {
                elId = el.ElementType + '-' + el.Id;
            } else {
                elId = 'element-' + el.Id;
            }

            this.DrawCanvas(elId);
            var canvas = document.getElementById(elId);

            // If defined, set attribute for element
            if(typeof attributeName !== 'undefined' && typeof attributeValue !== 'undefined') {
                canvas.setAttribute(attributeName, attributeValue);
            }

            // Set canvas for given element
            Object.defineProperties(el, {
                'Canvas': {
                    enumerable: true,
                    configurable: false,
                    writable: false,
                    value: canvas
                },
                'Context': {
                    enumerable: true,
                    configurable: false,
                    writable: false,
                    value: canvas.getContext('2d')
                }
            });

            // Set element's zIndex
            this.SetzIndexById(elId, 3);
        },

        CreateHtmlElement: function(el, attributes) {
            var tag = document.createElement(el);
            for(var attribute in attributes) {
                if(attributes.hasOwnProperty(attribute)) {
                    tag.setAttribute(attribute, attributes[attribute])
                }
            }
            document.getElementById('body').appendChild(tag);
        },

        /**
         * Creates new Canvas element in DOM
         * @param id
         * @param width
         * @param height
         * @constructor
         */
        DrawCanvas: function(id, width, height) {
            // For undefined width/height get window dimensions
            width = typeof width === 'undefined' ? window.innerWidth : width;
            height = typeof height === 'undefined' ? window.innerHeight : height;

            var el = document.createElement('canvas');
            el.setAttribute('id', id);
            el.setAttribute('width', width.toString());
            el.setAttribute('height', height.toString());
            document.getElementById('body').appendChild(el);

            // Set element's zIndex
            this.SetzIndexById(id, 1);
        },

        /**
         * Draws new rectangle with specific parameters
         * @param ctx
         * @param X
         * @param Y
         * @param width
         * @param height
         * @param background
         * @constructor
         * @param borderColor
         * @param borderWidth
         */
        DrawRectangle: function(ctx, X, Y, width, height, background, borderColor, borderWidth) {
            ctx.fillStyle = background;
            ctx.fillRect(X, Y, width, height);
            ctx.strokeStyle = borderColor;
            ctx.lineWidth = borderWidth;
            ctx.strokeRect(X, Y, width, height);
        },

        DrawRectangleWithText: function(ctx, X, Y, width, height, background, borderColor, borderWidth, text, textX, textY, textColor, textSize, textFont, textAlign) {
            this.DrawRectangle(ctx, X, Y, width, height, background, borderColor, borderWidth);
            this.DrawText(ctx, textX, textY, text, textColor, textSize, textFont, textAlign);
        },

        /**
         * Draw rounded rectangle with specific parameters
         * @param ctx
         * @param X
         * @param Y
         * @param width
         * @param height
         * @param background
         * @param arcSize
         * @constructor
         */
        DrawRoundedRectangle: function(ctx, X, Y, width, height, background, arcSize) {
            ctx.fillStyle = background;
            ctx.beginPath();
            ctx.moveTo(X + arcSize, Y);
            ctx.lineTo(X + width - arcSize, Y);
            ctx.arcTo(X + width, Y, X + width, Y + arcSize, arcSize);
            ctx.lineTo(X + width, Y + height - arcSize);
            ctx.arcTo(X + width, Y + height, X + width - arcSize, Y + height, arcSize);
            ctx.lineTo(X + arcSize, Y + height);
            ctx.arcTo(X, Y + height, X, Y - arcSize, arcSize);
            ctx.lineTo(X, Y + arcSize);
            ctx.arcTo(X, Y, X + arcSize, Y, arcSize);
            ctx.lineTo(X + arcSize, Y);
            ctx.fill();
        },

        DrawRoundedRectangleWithText: function(ctx, X, Y, width, height, background, arcSize, text, textX, textY, textColor, textSize, textFont, textAlign) {
            this.DrawRoundedRectangle(ctx, X, Y, width, height, background, arcSize);
            this.DrawText(ctx, textX, textY, text, textColor, textSize, textFont, textAlign);
        },

        DrawText: function(ctx, X, Y, text, textColor, textSize, textFont, textAlign) {
            ctx.fillStyle = textColor;
            ctx.font = textSize + ' ' +  textFont;
            ctx.textBaseline = 'top';
            ctx.textAlign = textAlign;
            ctx.fillText(text, X, Y);
        },

        /**
         * @return {number}
         * @return {number}
         */
        GenerateRandomInteger: function(min, max) {
            return Math.floor(Math.random() * (max - min + 1) + min);
        },

        /**
         * Generates unique ID
         * @returns {string}
         * @constructor
         */
        GenerateUUID: function() {
            return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
                var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
                return v.toString(16);
            });
        },

        /**
         * Sets parent's properties for child
         * @param parent
         * @param child
         * @constructor
         */
        InheritProperties: function(parent, child) {
            for(var property in parent) {
                if(parent.hasOwnProperty(property)) {
                    // Add property/value to child
                    child[property] = parent[property];
                }
            }
        },

        /**
         * Singularity substitute for Canvas.MeasureText since it
         * allows for much better calculations
         * @param text
         * @param bold
         * @param font
         * @param size
         * @returns {*}
         * @constructor
         */
        MeasureText: function(text, bold, font, size) {
            // This global variable is used to cache repeated calls with the same arguments
            var str = text + ':' + bold + ':' + font + ':' + size;
            if (typeof(__measuretext_cache__) == 'object' && __measuretext_cache__[str]) {
                return __measuretext_cache__[str];
            }

            var div = document.createElement('DIV');
            div.innerHTML = text;
            div.style.position = 'absolute';
            div.style.top = '-100px';
            div.style.left = '-100px';
            div.style.fontFamily = font;
            div.style.fontWeight = (bold == 'bold') ? 'bold' : 'normal';
            div.style.fontSize = size;
            document.body.appendChild(div);

            var measurement = { Width: div.offsetWidth, Height: div.offsetHeight };

            document.body.removeChild(div);

            // Add the sizes to the cache as adding DOM elements is costly and can cause slow downs
            if (typeof(__measuretext_cache__) != 'object') {
                __measuretext_cache__ = [];
            }
            __measuretext_cache__[str] = measurement;

            return measurement;
        },

        RedrawUIForClick: function(el) {
            // Clear UI stage
            this.ClearCanvas(el.Context, el.Canvas.width, el.Canvas.height);

            // Redraw element
            el.Add();
        },

        RemoveDomElementById: function(elId) {
            var body, el;
            el = document.getElementById(elId);
            body = document.getElementById('body');

            // Remove element
            body.removeChild(el);
        },

        RemoveDomElements: function(elType) {
            var _i, _length;

            // Delete elements
            var elements = document.getElementsByTagName(elType);
            for(_i = elements.length - 1, _length = 0; _i >= _length; _i = _i - 1) {
                document.body.removeChild(elements[_i]);
            }
        },

        /**
         * Sets given element's zIndex
         * @param id
         * @param zIndex
         * @constructor
         */
        SetzIndexById: function(id, zIndex) {
            document.getElementById(id).style.zIndex = zIndex;
        }
    };

    return Core.prototype;
});